#include "ftpTrans.h"
#include "curl/curl.h"
#include <cstring>
#include <algorithm>
#include <iterator>
#include "downloadHelp.h"
FtpTrans::FtpTrans()
{
	curl_global_init(CURL_GLOBAL_ALL);
	curlhandle = curl_easy_init();
	curldwn = curl_easy_init();
	files.resize(0);
}
FtpTrans::~FtpTrans()
{
	curl_easy_cleanup(curlhandle);
	curl_easy_cleanup(curldwn);
	curl_global_cleanup();
}

size_t getFTPFileList(void *ptr, size_t size, size_t nmemb, void *stream)
{
	printf("size_t getFTPFileList(void *ptr, size_t size, size_t nmemb, void *stream)\n");
	printf("ptr = %s\n", (char *)ptr);
}

size_t getcontentlengthfunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
	int r;
	long len = 0;
	r = sscanf((const char *)ptr, "Content-length:%1d\n", &len);
	if (r)
		*((long *)stream) = len;
	return size * nmemb;
}
size_t discardfunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
	return size * nmemb;
}
size_t readfunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
	FILE *f = (FILE *)stream;
	size_t n;
	if (ferror(f))
		return CURL_READFUNC_ABORT;
	n = fread(ptr, size, nmemb, f) * size;
	return n;
}
size_t writefunc(void *ptr, size_t size, size_t nmemb, void *stream)
{
	return fwrite(ptr, size, nmemb, (FILE *)stream);
}
int FtpTrans::login(const char *ip, const char *user, const char *pwd, long timeout)
{
	char *str = (char *)malloc(strlen(user) + strlen(pwd) + strlen(":") + 1);
	strcpy(str, user);
	strcat(str, ":");
	strcat(str, pwd);
	if (curlhandle != NULL)
	{
		curl_easy_setopt(curlhandle, CURLOPT_URL, ip);
		curl_easy_setopt(curlhandle, CURLOPT_USERPWD, str);
		delete[] str;
		str = NULL;
		if (timeout)
		{
			curl_easy_setopt(curlhandle, CURLOPT_FTP_RESPONSE_TIMEOUT, timeout);
		}
		return 0;
	}
	else
	{
		return 2;
	}
}
int FtpTrans::logout()
{
	/*curl_easy_cleanup(curlhandle);
	curl_easy_cleanup(curldwn);*/
	return 0;
}
vector<const char *> FtpTrans::enumDirectory(const char *filename)
{
	return files;
}
int FtpTrans::upload(const char *remotepath, const char *localpath, long tries)
{
	FILE *f;
	long uploaded_len = 0;
	CURLcode r = CURLE_GOT_NOTHING;
	int c;
	f = fopen(localpath, "rb");
	if (f == NULL)
	{
		perror(NULL);
		return 0;
	}
	curl_easy_setopt(curlhandle, CURLOPT_UPLOAD, 1L);
	curl_easy_setopt(curlhandle, CURLOPT_URL, remotepath);
	curl_easy_setopt(curlhandle, CURLOPT_HEADERFUNCTION, getcontentlengthfunc);
	curl_easy_setopt(curlhandle, CURLOPT_HEADERDATA, &uploaded_len);
	curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, discardfunc);
	curl_easy_setopt(curlhandle, CURLOPT_READFUNCTION, readfunc);
	curl_easy_setopt(curlhandle, CURLOPT_READDATA, f);
	curl_easy_setopt(curlhandle, CURLOPT_FTPPORT, "-"); /* disable passive mode */
	curl_easy_setopt(curlhandle, CURLOPT_FTP_CREATE_MISSING_DIRS, 1L);
	curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1L);
	for (c = 0; (r != CURLE_OK) && (c < tries); c++)
	{
		if (c)
		{ /* yes */
			/* determine the length of the file already written */
			/*
			 * With NOBODY and NOHEADER, libcurl will issue a SIZE
			 * command, but the only way to retrieve the result is
			 * to parse the returned Content-Length header. Thus,
			 * getcontentlengthfunc(). We need discardfunc() above
			 * because HEADER will dump the headers to stdout
			 * without it.
			 */
			curl_easy_setopt(curlhandle, CURLOPT_NOBODY, 1L);
			curl_easy_setopt(curlhandle, CURLOPT_HEADER, 1L);
			r = curl_easy_perform(curlhandle);
			if (r != CURLE_OK)
				continue;
			curl_easy_setopt(curlhandle, CURLOPT_NOBODY, 0L);
			curl_easy_setopt(curlhandle, CURLOPT_HEADER, 0L);
			fseek(f, uploaded_len, SEEK_SET);
			curl_easy_setopt(curlhandle, CURLOPT_APPEND, 1L);
		}
		else
		{ /* no */
			curl_easy_setopt(curlhandle, CURLOPT_APPEND, 0L);
		}
		r = curl_easy_perform(curlhandle);
	}
	fclose(f);
	if (r == CURLE_OK)
		return 1;
	else
	{
		fprintf(stderr, "%s\n", curl_easy_strerror(r));
		return 0;
	}
}
int FtpTrans::download(const char *remotepath, const char *localpath, long tries)
{
	FILE *f;
	curl_off_t local_file_len = -1;
	long filesize = 0;
	CURLcode r = CURLE_GOT_NOTHING;
	struct stat file_info;
	int use_resume = 0;
	// 获取本地文件大小信息
	if (stat(localpath, &file_info) == 0)
	{
		local_file_len = file_info.st_size;
		use_resume = 1;
	}
	// 追加方式打开文件，实现断点续传
	f = fopen(localpath, "ab+");
	if (f == NULL)
	{
		perror(NULL);
		return 0;
	}
	curl_easy_setopt(curlhandle, CURLOPT_URL, remotepath);
	curl_easy_setopt(curlhandle, CURLOPT_HEADERFUNCTION, getcontentlengthfunc);
	curl_easy_setopt(curlhandle, CURLOPT_HEADERDATA, &filesize);
	curl_easy_setopt(curlhandle, CURLOPT_RESUME_FROM_LARGE, use_resume ? local_file_len : 0);
	curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, writefunc);
	curl_easy_setopt(curlhandle, CURLOPT_WRITEDATA, f);
	curl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1L);
	curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1L);
	curl_easy_perform(curlhandle);
	fclose(f);
	if (r == CURLE_OK)
		return 1;
	else
	{
		fprintf(stderr, "%s\n", curl_easy_strerror(r));
		return 0;
	}
}

int FtpTrans::getFtpServerDir(const char *url, const char *pwd, long tries)
{
}

int FtpTrans::dirlist(const char *url, const char *remote, std::vector<FILE_INFO> &vecFileInfo)
{
	if (curlhandle == NULL)
	{
		fprintf(stderr, "%s\n", "curlhandle error");
		return -1;
	}
	curl_easy_setopt(curlhandle, CURLOPT_URL, url);
	curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1L);
	curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, write_data);
	std::string response;
	curl_easy_setopt(curlhandle, CURLOPT_WRITEDATA, &response);
	CURLcode code = curl_easy_perform(curlhandle);
	if (code != CURLE_OK)
	{
		auto m_lastError = curl_easy_strerror(code);
		printf("ftp connect failure: %s!\n", m_lastError);
		return -1;
	}
	std::string::size_type pos = 0, index = 0, len = 0;
	while (true)
	{
		std::string row = "";

		pos = response.find("\n", pos) + 2;

		if (pos < index)
		{
			break;
		}
		len = pos - index;				   // 需要截取的字符串长度
		row = response.substr(index, len); // 得到每行数据
		index = pos;
		std::string::size_type rowPos = 0, rowIndex = 0, rowLen = 0;
		// 得到名称
		FILE_INFO fileInfo;
		rowPos = row.find_last_of(' ') + 1;
		cout << "response = " << row << "   " << rowPos << endl;
		std::string name = row.substr(rowPos, row.length());
		if (name.size() == 0 || name[0] == '.')
		{
			continue;
		}

		cout << "name = " << name << endl;
		char ch = '\n';
		auto it = std::find(name.rbegin(), name.rend(), ch);
		cout << " pos  " << std::distance(name.begin(), (it + 1).base()) << std::endl;

		fileInfo.name = name.substr(0, std::distance(name.begin(), (it + 1).base()));
		// 得到文件权限和文件类型
		rowPos = row.find_first_of(' ');
		std::string data = row.substr(1, rowPos);
		if (data.size() != 0)
		{
			if (data[0] == 'd')
			{
				// 文件夹
				fileInfo.type = 0;
				fileInfo.permissions = data.substr(1, data.length());
			}
			else
			{
				// 文件
				fileInfo.type = 1;
				fileInfo.permissions = data.substr(1, data.length());
			}
		}

		vecFileInfo.push_back(fileInfo);
	}
	return 0;
}
